package com.hzhk.happyrent.ui.view.listview;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;

import com.hzhk.happyrent.R;
import com.hzhk.happyrent.utils.DensityUtils;


/**
 * maimai_a
 * cn.maitian.app.ui.view.listview
 *
 * @Author: xie
 * @Time: 2016/7/6 12:39
 * @Description:
 */

public class MaiTianListview extends ListView implements AbsListView.OnScrollListener {

    private final static int SCROLLBACK_HEADER = 0;
    private final static int SCROLLBACK_FOOTER = 1;
    private final static int SCROLL_DURATION = 200; // scroll back duration
    private final static int PULL_LOAD_MORE_DELTA = 30; // when pull up >= 70px
    private final static float OFFSET_RADIO = 1.8f; // support iOS like pull

    private boolean mIsFooterReady = false;
    private boolean mPullRefreshing = false;
    private float mLastY = -1;

    private OnResizeListener mOnResizeListener;
    private OnMaiTianRefreshListener mOnRefreshListener;
    private OnMaiTianPullUpRefreshListener mOnPullUpRefreshListener;
    private OnMaiTianPullDownRefreshListener mOnPullDownRefreshListener;
    private Scroller mScroller;
    private MaiTianListViewHeader mHeaderView;
    private RelativeLayout mHeaderViewContent;
    private XListViewFooter mFooterView;

    private boolean mFooterEnable = true;

    private boolean mPullLoading;
    private boolean mEnablePullLoad;
    private boolean mEnablePullRefresh;
    private int mHeaderViewHeight;
    private int mTotalItemCount;
    private int mScrollBack;
    private OnScrollListener mScrollListener; // user's scroll listener
    private Context context;
    private boolean jump;
    // 是否footer准备状态
    private boolean isFooterAdd = false;
    private boolean isHeader = false;

    public MaiTianListview(Context context) {
        super(context);
        this.context = context;
        init(context);
    }

    public MaiTianListview(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init(context);
    }

    public MaiTianListview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init(context);
    }

    private void init(Context context) {
        super.setOnScrollListener(this);
        mScroller = new Scroller(context, new DecelerateInterpolator());
        mHeaderView = new MaiTianListViewHeader(context);
        mHeaderViewContent = (RelativeLayout) mHeaderView.findViewById(R.id.rl_maitian_lv_header);
        setPullRefreshEnable(true);
        // init header height
        mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mHeaderViewHeight = mHeaderViewContent.getHeight();
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        });
        mFooterView = new XListViewFooter(context);
        setFooterDividersEnabled(false);
        setHeaderDividersEnabled(false);
        setPullLoadEnable(true);
    }

    private void invokeOnScrolling() {
        if (mScrollListener instanceof OnXScrollListener) {
            OnXScrollListener l = (OnXScrollListener) mScrollListener;
            l.onXScrolling(this);
        }
    }

    /**
     * reset header view's height.
     */
    private void resetHeaderHeight() {
        int height = mHeaderView.getVisiableHeight();
        if (height == 0) // not visible.
            return;
        // refreshing and header isn't shown fully. do nothing.
        int finalHeight = 0; // default: scroll back to dismiss header.
        // is refreshing, just scroll back to show all the header.
        if (mPullRefreshing && height > mHeaderViewHeight) {
            finalHeight = mHeaderViewHeight;
        }
        mScrollBack = SCROLLBACK_HEADER;

        mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION);
        if (!mPullRefreshing && jump) {
            mHeaderView.setState(MaiTianListViewHeader.STATE_COMPLETE);
        }
        invalidate();
    }

    private void resetFooterHeight() {
        int bottomMargin = mFooterView.getBottomMargin();
        if (bottomMargin > 0) {
            mScrollBack = SCROLLBACK_FOOTER;
            mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION);
            //            mScroller.abortAnimation();
            invalidate();
        }
    }

    private void startLoadMore() {
        mPullLoading = true;
        if (mFooterEnable) {
            mFooterView.setState(XListViewFooter.STATE_LOADING);
            if (mOnRefreshListener != null) {
                mOnRefreshListener.onLoadMore();
            } else if (mOnPullUpRefreshListener != null) {
                mOnPullUpRefreshListener.onLoadMore();
            }
        }
    }

    private void updateHeaderHeight(float delta) {
        mHeaderView.setVisiableHeight((int) delta + mHeaderView.getVisiableHeight());
        if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态，更新箭头
            if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
                mHeaderView.setState(MaiTianListViewHeader.STATE_READY);
            } else {
                mHeaderView.setState(MaiTianListViewHeader.STATE_NORMAL);

                //计算当前滑动的高度
                float currentHeight = mHeaderView.getVisiableHeight();
                //用当前滑动的高度和头部headerView的总高度进行比 计算出当前滑动的百分比 0到1
                float currentProgress = currentHeight / mHeaderViewHeight;
                //如果当前百分比大于1了，将其设置为1，目的是让第一个状态的椭圆不再继续变大
                if (currentProgress >= 1) {
                    currentProgress = 1;
                }

                mHeaderView.setAnimation(currentProgress);
            }
        }
        setSelection(0); // scroll to top each time
    }

    private void updateFooterHeight(float delta) {
        mFooterView.setBottomMargin((int) (mFooterView.getBottomMargin() + delta));
        if (mEnablePullLoad && !mPullLoading) {
            if (mFooterView.getBottomMargin() > DensityUtils.dp2px(context, PULL_LOAD_MORE_DELTA)) { // height enough to invoke load
                // more.
                mFooterView.setState(XListViewFooter.STATE_READY);
            } else {
                mFooterView.setState(XListViewFooter.STATE_NORMAL);
            }
        }
    }

    public boolean isPullLoading() {
        return mPullLoading;
    }

    public boolean isPullRefreshing() {
        return mPullRefreshing;
    }

    /**
     * 回调接口，想实现下拉刷新的listview实现此接口
     *
     * @param onRefreshListener
     */
    public void setOnMaiTianRefreshListener(OnMaiTianRefreshListener onRefreshListener) {
        mOnRefreshListener = onRefreshListener;
    }

    public void setOnMaiTianRefreshListener(OnMaiTianPullDownRefreshListener onRefreshListener) {
        mOnPullDownRefreshListener = onRefreshListener;
    }

    public void setOnMaiTianRefreshListener(OnMaiTianPullUpRefreshListener onRefreshListener) {
        mOnPullUpRefreshListener = onRefreshListener;
    }

    public void setOnResizeListener(OnResizeListener mOnResizeListener) {
        this.mOnResizeListener = mOnResizeListener;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (mScrollListener != null) {
            mScrollListener.onScrollStateChanged(view, scrollState);
        }
    }

    @Override
    public void setOnScrollListener(OnScrollListener l) {
        mScrollListener = l;
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        // send to user's listener
        mTotalItemCount = totalItemCount;
        if (mScrollListener != null) {
            mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        super.setAdapter(adapter);
    }

    public boolean getPullRefreshEnable() {
        return isHeader;
    }

    /**
     * @return void
     * @Title: setMaitianHeader
     * @Description: (设置header)
     * @params [b]
     */
    public void setPullRefreshEnable(boolean b) {
        if (mEnablePullRefresh == b) return;
        mEnablePullRefresh = b;
        if (!b) {
            isHeader = false;
            removeHeaderView(mHeaderView);
        } else {
            if (!isHeader) {
                isHeader = true;
                addHeaderView(mHeaderView);
            }
        }
    }

    public boolean getPullLoadEnable() {
        return isFooterAdd;
    }

    /**
     * enable or disable pull up load more feature.
     *
     * @param enable
     */
    public void setPullLoadEnable(boolean enable) {
        mFooterEnable = true;
        if (mEnablePullLoad == enable) return;
        mEnablePullLoad = enable;
        if (!enable) {
            isFooterAdd = false;
            removeFooterView(mFooterView);
            mFooterView.setOnClickListener(null);
        } else {
            mPullLoading = false;
            if (!isFooterAdd) {
                isFooterAdd = true;
                addFooterView(mFooterView);
                mFooterView.setState(XListViewFooter.STATE_NORMAL);
                // both "pull up" and "click" will invoke load more.
                mFooterView.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        startLoadMore();
                    }
                });
            }
        }
    }

    public void stop() {
        if (isPullLoading()) {
            stopLoadMore();
        }
        if (isPullRefreshing()) {
            stopRefresh();
        }
    }
    public void allLoadFinish() {
        if (isPullLoading()) {
            stopLoadMore();
        }
        if (isPullRefreshing()) {
            stopRefresh();
        }
        setFooterEnable(false);
        setFooterText(context.getString(R.string.all_load_complate));
    }

    public void setFooterVisible(boolean visible){
        if (visible) {
            mFooterView.setVisibility(VISIBLE);
        }else {
            mFooterView.setVisibility(INVISIBLE);
        }
    }
    public void stopRefresh() {
        if (mPullRefreshing == true) {
            jump = true;
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (mScroller != null) {
                        mPullRefreshing = false;
                        resetHeaderHeight();
                    }
                }
            }, SCROLL_DURATION);
            //            mHeaderView.setState(MaiTianListViewHeader.STATE_NORMAL);
        }
    }

    public void stopLoadMore() {
        if (mPullLoading == true) {
            mPullLoading = false;
            jump = true;
            mFooterView.setState(XListViewFooter.STATE_NORMAL);
            resetFooterHeight();
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            if (mScrollBack == SCROLLBACK_HEADER) {
                mHeaderView.setVisiableHeight(mScroller.getCurrY());
            } else {
                mFooterView.setBottomMargin(mScroller.getCurrY());
            }
            postInvalidate();
            invokeOnScrolling();
        }
        super.computeScroll();
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (mEnablePullRefresh == true || mEnablePullLoad == true) {
            if (mLastY == -1) {
                mLastY = ev.getRawY();
            }
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mLastY = ev.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float deltaY = ev.getRawY() - mLastY;
                    mLastY = ev.getRawY();
                    if (getFirstVisiblePosition() == 0 && !mPullRefreshing && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {
                        // the first item is showing, header has shown or pull down.
                        if (mHeaderView.getVisiableHeight() > DensityUtils.dp2px(context, 150))
                            if (deltaY > 0) deltaY = 0;
                        updateHeaderHeight(deltaY / OFFSET_RADIO);
                        invokeOnScrolling();
                    } else if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) {
                        // last item, already pulled up or want to pull up.
                        if (mFooterView.getBottomMargin() > DensityUtils.dp2px(context, 90))
                            if (deltaY < 0) deltaY = 0;
                        updateFooterHeight(-deltaY / OFFSET_RADIO);
                        invokeOnScrolling();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    mLastY = -1; // reset
                    if (getFirstVisiblePosition() == 0) {
                        // invoke refresh
                        if (mEnablePullRefresh && !mPullRefreshing && mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
                            mPullRefreshing = true;
                            mHeaderView.setState(MaiTianListViewHeader.STATE_REFRESHING);
                            if (mOnRefreshListener != null) {
                                mOnRefreshListener.onRefresh();
                            } else if (mOnPullDownRefreshListener != null) {
                                mOnPullDownRefreshListener.onRefresh();
                            }
                        }
                        resetHeaderHeight();
                    } else if (getLastVisiblePosition() == mTotalItemCount - 1) {
                        // invoke load more.
                        if (mEnablePullLoad && mFooterView.getBottomMargin() > DensityUtils.dp2px(context, PULL_LOAD_MORE_DELTA) && !mPullLoading) {
                            startLoadMore();
                        }
                        resetFooterHeight();
                    }
                    break;
            }
        }
        return super.onTouchEvent(ev);
    }

    public void setHeaderText(String headerDown, String headerReady, String headerUp) {
        mHeaderView.headerDown = headerDown;
        mHeaderView.headerReady = headerReady;
        mHeaderView.headerUp = headerUp;
    }

    public void setFooterEnable(boolean enable) {
        setPullLoadEnable(true);
        mFooterEnable = enable;
        mFooterView.setClickable(enable);
        mFooterView.setEnabled(enable);
    }

    public void setFooterText(String hint) {
        mFooterView.setHint(hint);
    }

    public void setAutoRefresh(boolean isRefresh) {
        if (isRefresh) {
            mLastY = -1; // reset
            // 判断是否在第一行，如果不是第一行，则不执行
            if (getFirstVisiblePosition() == 0) {
                // invoke refresh
                if (mEnablePullRefresh && mPullRefreshing != true) {
                    mPullRefreshing = true;
                    mScrollBack = SCROLLBACK_HEADER;
                    updateHeaderHeight(DensityUtils.dp2px(context, 70.5f));
                    mHeaderView.setState(MaiTianListViewHeader.STATE_REFRESHING);
                    invokeOnScrolling();
                    //                    if (mOnRefreshListener != null) {
                    //                        mOnRefreshListener.onRefresh();
                    //                    } else if (mOnPullDownRefreshListener != null) {
                    //                        mOnPullDownRefreshListener.onRefresh();
                    //                    }
                }
            }
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (mPullRefreshing && mScroller != null) {
                        resetHeaderHeight();
                    }
                }
            }, SCROLL_DURATION);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mOnResizeListener != null) mOnResizeListener.onResize(w, h, oldw, oldh);
    }

    public interface OnResizeListener {
        void onResize(int w, int h, int oldw, int oldh);
    }

    public interface OnMaiTianRefreshListener {
        void onRefresh();

        void onLoadMore();
    }

    public interface OnMaiTianPullDownRefreshListener {
        void onRefresh();
    }

    public interface OnMaiTianPullUpRefreshListener {
        void onLoadMore();
    }

    /**
     * you can listen ListView.OnScrollListener or this one. it will invoke
     * onXScrolling when header/footer scroll back.
     */
    public interface OnXScrollListener extends OnScrollListener {
        void onXScrolling(View view);
    }

    public void setListView(AdapterView listView) {
        this.listView = listView;
    }

    private AdapterView listView;
    private float xDistance, yDistance, xLast, yLast;
    /**
     * 覆写onInterceptTouchEvent方法，点击操作发生在ListView的区域的时候,
     * 返回false让ScrollView的onTouchEvent接收不到MotionEvent，而是把Event传到下一级的控件中
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        if (listView != null && checkArea(listView, ev)) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    xDistance = yDistance = 0f;
                    xLast = ev.getX();
                    yLast = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    final float curX = ev.getX();
                    final float curY = ev.getY();

                    xDistance += Math.abs(curX - xLast);
                    yDistance += Math.abs(curY - yLast);
                    xLast = curX;
                    yLast = curY;

                    if (xDistance > yDistance) {
                        return false;
                    }
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

    /**
     *  测试view是否在点击范围内
     * @param
     * @param v
     * @return
     */
    private boolean checkArea(View v, MotionEvent event){
        float x = event.getRawX();
        float y = event.getRawY();
        int[] locate = new int[2];
        v.getLocationOnScreen(locate);
        int l = locate[0];
        int r = l + v.getWidth();
        int t = locate[1];
        int b = t + v.getHeight();
        if (l < x && x < r && t < y && y < b) {
            return true;
        }
        return false;
    }
}
